<?php
namespace app\manage\service;

use app\manage\service\ApiSuper;
/**
 * api中除服务类以外的所有类的父类,
 * 在其子类中,应避免使用$_GET,$_POST,及cookie中的数据,所有的数据应从类属性中获得
 * @author   李全春   <adv30@126.com>  <time:2016年4月17日14时31分50秒>
 *
 */
class ApiBase extends ApiSuper
{

    protected $jsonData  = null;     //app传过来的非文件数据,默认为json字符串转成的josn对象
    protected $arrData   = null;     //app传过来的非文件数据,默认为json字符串转成的array

    // 逻辑层池
    protected $logicPond = [];

    public function __construct( $textData = null, $fileData = null, $encryption = null )
    {
        if( !is_null($textData) ){
            // $this->textData = $textData;
            // $this->jsonData = json_decode( $textData );
            $this->arrData  = json_decode( $textData, TRUE );
        }
        $this->fileData   = $fileData;
        $this->encryption = $encryption;
    }
    // 自动执行验证和逻辑层
    protected function stepRun(array $data, string $methods, string $scene = '', string $validate = '', string $logic = ''): array
    {
        if ('' === $validate || '' === $logic){
            $classArr = explode('\\', get_class($this));
            $class = lcfirst($classArr[count($classArr) - 1]);
            if ('' === $validate){
                $validate = $this->{$class . 'Validate'};
            }

            if ('' === $logic) {
                $logic = $this->{$class . 'Logic'};
            }
        }

        $validateObj = validate($validate);
        if (! ($validateObj->scene($scene)->check($data))) {
            return verify_err($data, $validateObj->getError());
        }
        return $this->logic($logic)->$methods($data);
    }
    // 新的一个参数的stepRun
    protected function newStepRun (array $param)
    {
        $data = $param['data'];
        $methods = $param['methods'];
        $scene = isset($param['scene']) ? $param['scene'] : '';
        $validate = isset($param['validate']) ? $param['validate'] : '';
        $logic = isset($param['logic']) ? $param['logic'] : '';
        return $this->stepRun($data, $methods, $scene, $validate, $logic);
    }
    // 返回逻辑层
    protected function logic ($path): \app\manage\logic\BaseLogic
    {
        $key = md5($path);
        return $this->logicPond[$key] ?? $this->logicPond[$key] = logic($path);
    }

    /*
    参数形式： ['name' => '默认名称']
    等同： isset($this->arrData['name']) && $data['name'] = $this->arrData['name'] ? $this->arrData['name'] : '默认名称';
    */
    public function issetReceiveData(array $default = [], array $val=['0', 0], bool $type=true): array
    {
        $res = [];
        foreach ($default as $k => $v) {
            if(isset($this->arrData[$k])){
                if(in_array($this->arrData[$k], $val, $type)){
                    $res[$k] = $this->arrData[$k];
                }else{
                    $res[$k] = $this->arrData[$k] ? $this->arrData[$k] : $v;
                }
            }
        }
        return $res;
    }

    /*
    参数形式： ['name' => '默认名称']
    等同： $data['name'] = $this->arrData['name'] ?? '默认名称';   //用于：该name字段可以不传，但需要添加name值
    */
    public function haveIssetReceiveData(array $default = [], array $val = ['0', 0 , ''], $type = true): array
    {
        $res = [];
        foreach ($default as $k => $v) {
            $res[$k] = isset($this->arrData[$k]) && !in_array($this->arrData[$k], $val, $type) ? $this->arrData[$k] : $v;
        }
        return $res;
    }
    /*
    参数形式： ['name' => '默认名称']
    等同：$data['name'] = $this->arrData['name'] ? $this->arrData['name'] : '默认名称';
    */
    public function receiveData(array $default = [], array $val=['0', 0], bool $type=true): array
    {
        $res = [];
        foreach ($default as $k => $v) {
            if(in_array($this->arrData[$k], $val, $type)){
                $res[$k] = $this->arrData[$k];
            }else{
                $res[$k] = $this->arrData[$k] ? $this->arrData[$k] : $v;
            }
        }
        return $res;
    }

    /*
     * 将传入的字段数组 根据转为另一个如 ['aaa' => 'ccc'] => ['bbb' => 'ccc'] 
     * @param $default ['aaa' => 'bbb'] 存转换前的键和转换后的键
     * @param $beforeAction 在接收此方法之前,预处理方法
     * @param #beforeParam 预处理参数据
     */ 
    public function changeKeyData(array $default = [], string $beforeAction = '', array $beforeParam = []): array
    {
        $data = $this->arrData;
        if ($beforeAction !== '' && is_callable([$this, $beforeAction])) {
            $data = $this->$beforeAction($beforeParam);
        }

        $res = [];
        foreach ($default as $k => $v){
            $res[$k] = $data[$v];
        }
        return $res;
    }
    /**
     *  生成发送的数据,可以签名等
     * @param  array   $data       [要发送的数据]
     * @param  bool    $encryption [是否加密]
     * @param  string  $sign       [签名的方法名]
     * @param  string  $ver        [签名的版本]
     * @return array               [description]
     */
    public function createData(array $data,bool $encryption = false, string $sign='signPublic', string $ver='ver1' ){
        $data['encryption'] = $encryption ? 'on' : 'off';
        $data['sendTime']   = NOW;
        $key                = $data['key'] ? $data['key'] : $data['sendTime'];
        $data['expiry']     = $data['expiry'] ? $data['expiry'] : 0;

        //如果是加密
        if( $encryption && isset( $data['textData'] ) ){
            $data['textData'] = $this->authCode( $data['textData'], 'ECODE', $key, $data['expiry'] );
        }

        //生成appkey
        $data['appkey'] =  $this->$sign( $data['sendTime'], $ver, $data['encryption'], $data['module'], $data['controller'], $data['action'] );

        return $data;
    }

    /**
     * 把数据发送给指定url,示例如下
     *  $url = 'http://bigmall.local/api_1.html';
     *  $data = array(
     *       "module"=>"user",
     *       "controller"=>"apiuser",
     *       "action"=>"userInfo",
     *       "textData"=>'{"userId":"1"}'
     *   );
     *  $sendObj = new ApiBase();
     *  $data = $sendObj->createData( $data, true );
     *  $res = $sendObj->sendData($url,$data );
     *
     * @param  array    $data       [要发送的数据,数组,键值对]
     * @param  array    $headerData [要设置的头,键值对]
     * @return bool     $res        [返回发送状态]
     */
    public function sendData(string $url, array $data, string $sessionId='' ){
        //1.初始化
        $ch = curl_init ();
        //2.设置
        curl_setopt ( $ch, CURLOPT_URL, $url );
        curl_setopt ( $ch, CURLOPT_POST, 1 );
        curl_setopt ( $ch, CURLOPT_HEADER, 0 );
        if( $sessionId ){
             curl_setopt ( $ch, CURLOPT_COOKIE, 'PHPSESSID=' . $sessionId  );
        }

        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
        //3.抓取URL并把它传递给浏览器
        $output = curl_exec( $ch );
        //4.关闭cURL资源，并且释放系统资源
        curl_close( $ch );
        return json_decode( $output, true );
    }

    // 获取一个app_key app_key以后可以从redis中读取
    public static function getAppKey() {
        return config('yayi_admin_app_key');
    }

    // 获取总后台的app_id
    public static function getAppId() {
        return config('yayi_admin_app_id');
    }

}
